#ifndef _PARAMETER_MCU_H
#define _PARAMETER_MCU_H
#include <lib/cassert.h>
#include "parameter.h"

typedef struct ddr_spd {
    /******************* read from spd *****************/
    uint8_t  dimm_type;     /* 1: RDIMM;2: UDIMM;3: SODIMM;4: LRDIMM */
    uint8_t  data_width;      /* 0: x4; 1: x8; 2: x16 */
    uint8_t  mirror_type;     /* 0: stardard; 1: mirror */
    uint8_t  ecc_type;       /* 0: no-ecc; 1:ecc */
    uint8_t  dram_type;       /* 0xB: DDR3; 0xC: DDR4 0x10: LPDDR4*/
    uint8_t  rank_num;
    uint8_t  row_num;
    uint8_t  col_num;

    uint8_t  bg_num;		/*only DDR4*/
    uint8_t  bank_num;
    uint16_t module_manufacturer_id;
    uint16_t tAAmin;
    uint16_t tRCDmin;

    uint16_t tRPmin;
    uint16_t tRASmin;
    uint16_t tRCmin;
    uint16_t tFAWmin;

    uint16_t tRRD_Smin;		/*only DDR4*/
    uint16_t tRRD_Lmin;		/*only DDR4*/
    uint16_t tCCD_Lmin;		/*only DDR4*/
    uint16_t tWRmin;

    uint16_t tWTR_Smin;		/*only DDR4*/
    uint16_t tWTR_Lmin;		/*only DDR4*/
    uint16_t tWTRmin;		/*only DDR3*/
    uint16_t tRRDmin;		/*only DDR3*/

    /******************* RCD control words *****************/
    uint8_t  F0RC03; /*bit[3:2]:CS         bit[1:0]:CA  */
    uint8_t  F0RC04; /*bit[3:2]:ODT        bit[1:0]:CKE */
    uint8_t  F0RC05; /*bit[3:2]:CLK-A side bit[1:0]:CLK-B side */
    uint8_t  BC00;
    uint8_t  BC01;
    uint8_t  BC02;
    uint8_t  BC03;
    uint8_t  BC04;

    uint8_t  BC05;
    uint8_t  F5BC5x;
    uint8_t  F5BC6x;
/******************* LRDIMM special *****************/
    uint8_t  vrefDQ_PR0;  /*Byte 140 (0x08C) (Load Reduced): DRAM VrefDQ for Package Rank 0*/
    uint8_t  vrefDQ_MDRAM;/* Byte 144 (0x090) (Load Reduced): Data Buffer VrefDQ for DRAM Interface*/
    uint8_t  RTT_MDRAM_1866; /*Byte 145 (0x091) (Load Reduced): Data Buffer MDQ Drive Strength and RTT for data rate < 1866 */
    uint8_t  RTT_MDRAM_2400; /*Byte 146 (0x092) (Load Reduced): Data Buffer MDQ Drive Strength and RTT for 1866<datarate<2400 */
    uint8_t  RTT_MDRAM_3200; /*Byte 147 (0x093) (Load Reduced): Data Buffer MDQ Drive Strength and RTT for 2400<datarate<3200 */

    uint8_t  Drive_DRAM;  /*Byte 148 (0x094) (Load Reduced): DRAM Drive Strength */
    uint8_t  ODT_DRAM_1866; /* Byte 149 (0x095) (Load Reduced): DRAM ODT (RTT_WR and RTT_NOM) for data rate < 1866 */
    uint8_t  ODT_DRAM_2400; /* Byte 150 (0x096) (Load Reduced): DRAM ODT (RTT_WR and RTT_NOM) for 1866 < data rate < 2400 */
    uint8_t  ODT_DRAM_3200; /* Byte 151 (0x097) (Load Reduced): DRAM ODT (RTT_WR and RTT_NOM) for 2400 < data rate < 3200 */
    uint8_t  PARK_DRAM_1866; /* Byte 152 (0x098) (Load Reduced): DRAM ODT (RTT_PARK) for data rate < 1866 */
    uint8_t  PARK_DRAM_2400; /* Byte 153 (0x099) (Load Reduced): DRAM ODT (RTT_PARK) for 1866 < data rate < 2400 */
    uint8_t  PARK_DRAM_3200; /* Byte 154 (0x09A) (Load Reduced): DRAM ODT (RTT_PARK) for 2400 < data rate  < 3200 */
    uint8_t  rcd_num;   /* Registers used on RDIMM */

}__attribute__((aligned(sizeof(unsigned long)))) ddr_spd_info_t;

typedef struct mcu_config {
    uint32_t magic;
	uint32_t version;
	uint32_t size;
	uint8_t rev1[4];

    uint8_t ch_enable;
    uint8_t ecc_enable;
    uint8_t dm_enable;
	uint8_t force_spd_enable;
    uint8_t misc_enable;	/*0:read spd req 1:use margin 2: s3 back devinit 3: cmd 2T mode 4:dual dimm*/
    uint8_t train_debug;
    uint8_t train_recover;	/*为1时跳过training*/

    uint8_t rev2[9];

    ddr_spd_info_t ddr_spd_info[2];
}__attribute__((aligned(sizeof(unsigned long)))) mcu_config_t;

#define MCU_MAGIC_OFFSET					0x0
#define MCU_VERSION_OFFSET					0x4
#define MCU_SIZE_OFFSET						0x8
#define MCU_CH_ENABLE_OFFSET				0x10
#define MCU_ECC_ENABLE_OFFSET				0x11
#define MCU_DM_ENABLE_OFFSET				0x12
#define MCU_FORCE_SPD_ENABLE_OFFSET			0x13
#define MCU_MISC_ENABLE_OFFSET				0x14
#define MCU_TRAIN_DEBUG_OFFSET				0x15
#define MCU_TRAIN_RECOVER_OFFSET			0x16

#define MCU_SPD0_INFO_OFFSET				0x20
#define MCU_SPD1_INFO_OFFSET				0x60

#define MCU_DIMM_TYPE_OFFSET				0x0
#define MCU_DATA_WIDTH_OFFSET				0x1
#define MCU_MIRROR_TYPE_OFFSET				0x2
#define MCU_ECC_TYPE_OFFSET					0x3
#define MCU_DRAM_TYPE_OFFSET				0x4
#define MCU_RANK_NUM_OFFSET					0x5
#define MCU_ROW_NUM_OFFSET					0x6
#define MCU_COL_NUM_OFFSET					0x7

#define MCU_BG_NUM_OFFSET					0x8
#define MCU_BANK_NUM_OFFSET					0x9
#define MCU_MODULE_OFFSET					0xa
#define MCU_TAA_MIN_OFFSET					0xc
#define MCU_TRCD_MIN_OFFSET					0xe

#define MCU_TRP_MIN_OFFSET					0x10
#define MCU_TRAS_MIN_OFFSET					0x12
#define MCU_TRC_MIN_OFFSET					0x14
#define MCU_TFAW_MIN_OFFSET					0x16

#define MCU_TRRD_S_MIN_OFFSET				0x18
#define MCU_TRRD_L_MIN_OFFSET				0x1a
#define MCU_TCCD_L_MIN_OFFSET				0x1c
#define MCU_TWR_MIN_OFFSET					0x1e

#define MCU_TWTR_S_MIN_OFFSET				0x20
#define MCU_TWTR_L_MIN_OFFSET				0x22
#define MCU_TWTR_MIN_OFFSET					0x24
#define MCU_TRRD_MIN_OFFSET					0x26

#define MCU_F0RC03_OFFSET					0x28
#define MCU_F0RC04_OFFSET					0x29
#define MCU_F0RC05_OFFSET					0x2a
#define MCU_BC00_OFFSET						0x2b
#define MCU_BC01_OFFSET						0x2c
#define MCU_BC02_OFFSET						0x2d
#define MCU_BC03_OFFSET						0x2e
#define MCU_BC04_OFFSET						0x2f

#define MCU_BC05_OFFSET						0x30
#define MCU_F5BC5x_OFFSET					0x31
#define MCU_F5BC6x_OFFSET					0x32
#define MCU_VREFDQ_PR0_OFFSET				0x33
#define MCU_VREFDQ_DRAM_OFFSET				0x34
#define MCU_RTT_MDRAM_1866_OFFSET			0x35
#define MCU_RTT_MDRAM_2400_OFFSET			0x36
#define MCU_RTT_MDRAM_3200_OFFSET			0x37

#define MCU_DRIVE_DRAM_OFFSET				0x38
#define MCU_ODT_DRAM_1866_OFFSET			0x39
#define MCU_ODT_DRAM_2400_OFFSET			0x3a
#define MCU_ODT_DRAM_3200_OFFSET			0x3b
#define MCU_PARK_DRAM_1866_OFFSET			0x3c
#define MCU_PARK_DRAM_2400_OFFSET			0x3d
#define MCU_PARK_DRAM_3200_OFFSET			0x3e
#define MCU_RCD_NUM_OFFSET					0x3f

#define CM_CASSERT( offset, _member)						\
	 CASSERT(offset ==										\
		 __builtin_offsetof(mcu_config_t, _member),			\
		 assert_##offset##_mismatch)
#define CM_CASSERT_CH( offset, _member)						\
	 CASSERT(offset ==										\
		 __builtin_offsetof(ddr_spd_info_t, _member),			\
		 assert_##_offset##_mismatch)

CM_CASSERT(MCU_MAGIC_OFFSET,				magic);
CM_CASSERT(MCU_VERSION_OFFSET,				version);
CM_CASSERT(MCU_SIZE_OFFSET,					size);
CM_CASSERT(MCU_CH_ENABLE_OFFSET,			ch_enable);
CM_CASSERT(MCU_ECC_ENABLE_OFFSET,			ecc_enable);
CM_CASSERT(MCU_DM_ENABLE_OFFSET,			dm_enable);
CM_CASSERT(MCU_FORCE_SPD_ENABLE_OFFSET,		force_spd_enable);
CM_CASSERT(MCU_MISC_ENABLE_OFFSET,			misc_enable);
CM_CASSERT(MCU_TRAIN_DEBUG_OFFSET,			train_debug);
CM_CASSERT(MCU_TRAIN_RECOVER_OFFSET,		train_recover);
CM_CASSERT(MCU_SPD0_INFO_OFFSET,			ddr_spd_info[0]);
CM_CASSERT(MCU_SPD1_INFO_OFFSET,			ddr_spd_info[1]);

CM_CASSERT_CH(MCU_DIMM_TYPE_OFFSET,			dimm_type);
CM_CASSERT_CH(MCU_DATA_WIDTH_OFFSET,		data_width);
CM_CASSERT_CH(MCU_MIRROR_TYPE_OFFSET,		mirror_type);
CM_CASSERT_CH(MCU_ECC_TYPE_OFFSET,			ecc_type);
CM_CASSERT_CH(MCU_DRAM_TYPE_OFFSET,			dram_type);
CM_CASSERT_CH(MCU_RANK_NUM_OFFSET,			rank_num);
CM_CASSERT_CH(MCU_ROW_NUM_OFFSET,			row_num);
CM_CASSERT_CH(MCU_COL_NUM_OFFSET,			col_num);

CM_CASSERT_CH(MCU_BG_NUM_OFFSET,			bg_num);
CM_CASSERT_CH(MCU_BANK_NUM_OFFSET,			bank_num);
CM_CASSERT_CH(MCU_MODULE_OFFSET,			module_manufacturer_id);
CM_CASSERT_CH(MCU_TAA_MIN_OFFSET,			tAAmin);
CM_CASSERT_CH(MCU_TRCD_MIN_OFFSET,			tRCDmin);

CM_CASSERT_CH(MCU_TRP_MIN_OFFSET,			tRPmin);
CM_CASSERT_CH(MCU_TRAS_MIN_OFFSET,			tRASmin);
CM_CASSERT_CH(MCU_TRC_MIN_OFFSET,			tRCmin);
CM_CASSERT_CH(MCU_TFAW_MIN_OFFSET,			tFAWmin);

CM_CASSERT_CH(MCU_TRRD_S_MIN_OFFSET,		tRRD_Smin);
CM_CASSERT_CH(MCU_TRRD_L_MIN_OFFSET,		tRRD_Lmin);
CM_CASSERT_CH(MCU_TCCD_L_MIN_OFFSET,		tCCD_Lmin);
CM_CASSERT_CH(MCU_TWR_MIN_OFFSET,			tWRmin);

CM_CASSERT_CH(MCU_TWTR_S_MIN_OFFSET,		tWTR_Smin);
CM_CASSERT_CH(MCU_TWTR_L_MIN_OFFSET,		tWTR_Lmin);
CM_CASSERT_CH(MCU_TWTR_MIN_OFFSET,			tWTRmin);
CM_CASSERT_CH(MCU_TRRD_MIN_OFFSET,			tRRDmin);

CM_CASSERT_CH(MCU_F0RC03_OFFSET,			F0RC03);
CM_CASSERT_CH(MCU_F0RC04_OFFSET,			F0RC04);
CM_CASSERT_CH(MCU_F0RC05_OFFSET,			F0RC05);
CM_CASSERT_CH(MCU_BC00_OFFSET,				BC00);
CM_CASSERT_CH(MCU_BC01_OFFSET,				BC01);
CM_CASSERT_CH(MCU_BC02_OFFSET,				BC02);
CM_CASSERT_CH(MCU_BC03_OFFSET,				BC03);
CM_CASSERT_CH(MCU_BC04_OFFSET,				BC04);

CM_CASSERT_CH(MCU_BC05_OFFSET,				BC05);
CM_CASSERT_CH(MCU_F5BC5x_OFFSET,			F5BC5x);
CM_CASSERT_CH(MCU_F5BC6x_OFFSET,			F5BC6x);
CM_CASSERT_CH(MCU_VREFDQ_PR0_OFFSET,		vrefDQ_PR0);
CM_CASSERT_CH(MCU_VREFDQ_DRAM_OFFSET,		vrefDQ_MDRAM);
CM_CASSERT_CH(MCU_RTT_MDRAM_1866_OFFSET,	RTT_MDRAM_1866);
CM_CASSERT_CH(MCU_RTT_MDRAM_2400_OFFSET,	RTT_MDRAM_2400);
CM_CASSERT_CH(MCU_RTT_MDRAM_3200_OFFSET,	RTT_MDRAM_3200);

CM_CASSERT_CH(MCU_DRIVE_DRAM_OFFSET,		Drive_DRAM);
CM_CASSERT_CH(MCU_ODT_DRAM_1866_OFFSET,		ODT_DRAM_1866);
CM_CASSERT_CH(MCU_ODT_DRAM_2400_OFFSET,		ODT_DRAM_2400);
CM_CASSERT_CH(MCU_ODT_DRAM_3200_OFFSET,		ODT_DRAM_3200);
CM_CASSERT_CH(MCU_PARK_DRAM_1866_OFFSET,	PARK_DRAM_1866);
CM_CASSERT_CH(MCU_PARK_DRAM_2400_OFFSET,	PARK_DRAM_2400);
CM_CASSERT_CH(MCU_PARK_DRAM_3200_OFFSET,	PARK_DRAM_3200);
CM_CASSERT_CH(MCU_RCD_NUM_OFFSET,			rcd_num);


/**************************************************************/

#define MCU_CH0_OFFSET	0
#define MCU_CH1_OFFSET	1

#define MCU_CH_ENABLE		0x1
#define MCU_CH_DISABLE		0x0

#define CH_ENABLE_INFO	((MCU_CH_ENABLE << MCU_CH0_OFFSET) | (MCU_CH_ENABLE << MCU_CH1_OFFSET))
#define ECC_ENABLE_INFO	0x1
#define DM_ENABLE_INFO	0x1

#define MCU_MIST_INFO   (   (CONFIG_FREQ_FROM_SPD_EN << 0)      |   \
                            (CONFIG_USE_MARGIN_EN << 1)         |   \
                            (CONFIG_USE_S3_DEVINIT_EN << 2)     |   \
                            (CONFIG_2T_TIMING_MODE_EN << 3)     |   \
                            (CONFIG_DUAL_DIMM_EN << 4)          |   \
                            (CONFIG_PERF_MODE_EN << 5)          |   \
                            (CONFIG_2T_PREAMBLE_MODE_EN << 6)       \
                        )

#endif

